// SKNotes - a note taking and gathering tool
// Copyright (C) 2009  Stefan Kueng
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

namespace SKNotes.Configuration
{
    using System;
    using System.Collections;
    using System.Reflection;

	public sealed class SettingCollection : IEnumerable
	{
		public SettingCollection( ApplicationSettings applicationSettings )
		{
			if ( applicationSettings == null )
			{
				throw new ArgumentNullException( "applicationSettings" );
			}

			this.applicationSettings = applicationSettings;
		}

		public ApplicationSettings ApplicationSettings
		{
			get { return this.applicationSettings; }
		} 

		public int Count
		{
			get { return this.settings.Count; }
		}

        public bool HasChanges
		{
			get 
			{
				foreach ( ISetting setting in this.settings )
				{
					if ( setting.HasChanged )
					{
						return true;
					}
				}
				return false;
			}
		}

		public IEnumerator GetEnumerator()
		{
			return this.settings.GetEnumerator();
		} 

		public bool Contains( ISetting setting )
		{
			if ( setting == null )
			{
				throw new ArgumentNullException( "setting" );
			}
			return this.settings.Contains( setting );
		}

		public void Add( ISetting setting )
		{
			if ( setting == null )
			{
				throw new ArgumentNullException( "setting" );
			}
			setting.ApplicationSettings = this.applicationSettings;
			this.settings.Add( setting );
		}

		public void AddAll( object obj )
		{
			if ( obj == null )
			{
				throw new ArgumentNullException( "obj" );
			}

			// field settings
			FieldInfo[] fieldInfos = obj.GetType().GetFields(
				BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );
			foreach ( FieldInfo fieldInfo in fieldInfos )
			{
				FieldSettingAttribute[] settingAttributes = (FieldSettingAttribute[])fieldInfo.GetCustomAttributes( typeof( FieldSettingAttribute ), true );
				if ( settingAttributes.Length <= 0 )
				{
					continue;
				}

				FieldSettingAttribute settingAttribute = settingAttributes[ 0 ];
				string settingName = settingAttribute.Name;
				if ( string.IsNullOrEmpty( settingName ) )
				{
					settingName = fieldInfo.Name;
				}
				object defaultValue = settingAttribute.DefaultValue;
				FieldSetting fieldSetting = new FieldSetting(
					settingName, obj, fieldInfo.Name, defaultValue );
				Add( fieldSetting );
			}

			// property settings
			PropertyInfo[] propertyInfos = obj.GetType().GetProperties(
				BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );
			foreach ( PropertyInfo propertyInfo in propertyInfos )
			{
				PropertySettingAttribute[] settingAttributes = (PropertySettingAttribute[])propertyInfo.GetCustomAttributes( typeof( PropertySettingAttribute ), true );
				if ( settingAttributes.Length <= 0 )
				{
					continue;
				}

				PropertySettingAttribute settingAttribute = settingAttributes[ 0 ];
				string settingName = settingAttribute.Name;
				if ( string.IsNullOrEmpty( settingName ) )
				{
					settingName = propertyInfo.Name;
				}
				object defaultValue = settingAttribute.DefaultValue;
				PropertySetting propertySetting = new PropertySetting(
					settingName, obj, propertyInfo.Name, defaultValue );
				Add( propertySetting );
			}
		}

		public void Remove( ISetting setting )
		{
			if ( setting == null )
			{
				throw new ArgumentNullException( "setting" );
			}
			this.settings.Remove( setting );
		}

		public void Clear()
		{
			this.settings.Clear();
		}

		private readonly ArrayList settings = new ArrayList();
		private readonly ApplicationSettings applicationSettings;

	}
}
